package com.me.myFramework.myAop.aop400;

import com.me.myFramework.myAop.aop400.advice.Advice;
import com.me.myFramework.myAop.aop400.advice.method.AfterReturningAdvice;
import com.me.myFramework.myAop.aop400.advice.method.MethodBeforeAdvice;
import com.me.myFramework.myAop.aop400.intercept.method.*;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.aop.Pointcut;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;

/**
 * 自己实现 AOP-4：  <p></p>
 *
 * 责任链实现多切面
 *
 * @author ME
 */
public class ProxyFactory implements InvocationHandler {

    /** 目标对象 */
    private final Object target;
    /** 目标类 */
    private final Class<?> targetClass;
    /**
     * 存放完整的切面对象（pointcut + advice）的集合
     */
    private final List<PointcutAdvisor> advisors = new ArrayList<>();

    public ProxyFactory(Object target) {
        this.target = target;
        this.targetClass = target.getClass();
    }

    /**
     * 动态代理织入增强逻辑，逻辑同 {@link org.springframework.aop.framework.JdkDynamicAopProxy#getProxy(java.lang.ClassLoader) JdkDynamicAopProxy#getProxy}
     */
    public Object getProxy(ClassLoader classLoader) {
        return Proxy.newProxyInstance(classLoader, target.getClass().getInterfaces(), this);
    }

    /**
     * 逻辑同 {@link org.springframework.aop.framework.JdkDynamicAopProxy#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[]) JdkDynamicAopProxy#invoke}
     *
     * @param proxy
     * @param method
     * @param args
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object retVal;

        // 筛选出当前正在执行的方法适用的 advice（切面），并转换成 拦截器（执行增强逻辑的执行器）
        List<MethodInterceptor> interceptorList = getInterceptors(method, targetClass);
        // TODO 切面处理逻辑，根据是否存在 切面执行器 判断执行 advice（增强）逻辑
        if (CollectionUtils.isNotEmpty(interceptorList)) {
            // 如果有执行切面的切面拦截器，则把拦截器传递给执行器（ReflectiveMethodInvocation），并借助执行器执行增强逻辑
            // （类似 FilterChain 责任链模式）
            MethodInvocation mi = new ReflectiveMethodInvocation(proxy, target, method, args, interceptorList);
            retVal = mi.proceed();
        }
        else {
            retVal = method.invoke(target, args);
        }

        return retVal;
    }

    /**
     * 筛选出当前正在执行的方法适用的 advice（增强），并转换成 拦截器（执行增强逻辑的执行器）。
     * 逻辑类似 {@link org.springframework.aop.framework.AdvisedSupport#getInterceptorsAndDynamicInterceptionAdvice(java.lang.reflect.Method, java.lang.Class) AdvisedSupport#getInterceptorsAndDynamicInterceptionAdvice}
     *
     * @param method        正在执行的方法
     * @param targetClass   目标类
     * @return  匹配当前方法的拦截器
     */
    private List<MethodInterceptor> getInterceptors(Method method, Class<?> targetClass) {
        List<MethodInterceptor> interceptorList = new ArrayList<>(this.advisors.size());
        for (PointcutAdvisor advisor : this.advisors) {
            Pointcut pointcut = advisor.getPointcut();
            if (pointcut.getClassFilter().matches(targetClass) && pointcut.getMethodMatcher().matches(method, targetClass)) {
                Advice advice = advisor.getAdvice();
                if (advice instanceof MethodBeforeAdvice) {
                    // Spring 中是通过适配器（MethodBeforeAdviceAdapter）把 advice转换成拦截器的
                    interceptorList.add(new MethodBeforeAdviceInterceptor((MethodBeforeAdvice) advice));
                }
                else if (advice instanceof AfterReturningAdvice) {
                    interceptorList.add(new AfterReturningAdviceInterceptor((AfterReturningAdvice) advice));
                }
                else {
                    throw new RuntimeException("未知的 advice类型");
                }
            }
        }

        return interceptorList;
    }

    /**
     * 添加一个切面类
     * @param advisor 完整的切面类（pointcut + advice）
     */
    public void addAdvisor(PointcutAdvisor advisor) {
        this.advisors.add(advisor);
    }
}
